<html xmlns="http://www.w3.org/1999/xhtml" id="custom-components">
<head>
    <title>カスタムコンポーネント</title>
</head>

<body>

<h1>カスタムコンポーネントをデザインする</h1>
 
<p>
コンポーネントとは、一般的にシンプルで使いやすい再使用可能なクラスのことです。Laszloで使われるコンポーネントの例としては、<classname>ボタン</classname>、<classname>ウィンドウ</classname>、<classname>タブスライダー</classname>などがあります。基本的な備え付けのコンポーネントは、<code>lps/components</code>ディレクトリのなかを見ると分かります。
</p>


<p>この章では、Laszloコンポーネントの使い方を知り、Laszloクラスについてよく理解し、リソース（資源）のインクルード（取り込み）方法を学び、LZXについて精通することができます。</p>

<h2>ベースコンポーネントとLZコンポーネント</h2>

<p>
基本的なコンポーネントには2種類あります。<dfn>ベースコンポーネント</dfn>と<dfn>lzコンポーネント</dfn>です。ベースコンポーネントは通常、不可視、抽象クラスです。Lzコンポーネントは可視クラスで、アートアセットを持ち、独自の見た目と感じを保持しています。
</p>

<p>クラスにはこのような区別があるので、コンポーネントの見た目と感じを完全にコントロールしつつ、なお一般的な動作に対し影響を及ぼすサブクラスを生成することができます。
場合によっては、継承された外観と相互作用動作を定義したいことがあるかもしれません。例えば、ウィンドウパネルクラスはウィンドウ、警告、そしてモーダルダイアログにより拡張されています。
</p>

<p>望まれるカスタムコンポーネントに見た目と感じとが合っているならば、lzコンポーネントはサブクラス化されるべきです。メソッドのマイナーチェンジと新しい外観の追加は素直なものであるべきです。例えば、頻繁に使われるアイコンボタンや特定の種類のリストアイテムのためにクラスを作りたければ、lzクラスをサブクラスにすべきです。完全に異なる見た目と感じが求められ、また/あるいは、lzクラスで見られるものとは機能的に大きく異なっている場合には、ベースコンポーネントをサブクラスにしてください。</p>

<p>理想としては、複雑なカスタムコンポーネントを書く場合、ベースクラス内で、可能な限りたくさんの不可視動作が実行されることが最良です。可視外観と、特にそれらの外観に適用される機能とは、目に見えるコンポーネントクラスに入れるべきです。こうするためには、たくさんの余分な努力が必要に思われますが、サブクラスが異なる見た目を持ちながらも、同じ機能を保持することによって、ベースクラスが再使用可能になることを促進するのです。例えば、<code>base/basebutton.lzx</code>と<code>lz/button.lzx</code>、また<code>base/baselist.lzx</code>と<code>lz/list.lzx</code>を比べてみてください。
</p>

<h2>サブクラス化するベースコンポーネントを決める</h2>

<p>カスタムコンポーネントを実行する大きな部分として、それがどのように使われるのかを理解するということがある。それはリストの一部なのか？値は保持するのか？このセクションでは、カスタムコンポーネントがどのベースクラスを使うべきかを決める方法を紹介します。
</p>

<p>ベースコンポーネントには基本的な4つのタイプがあります。</p>

<ul>
  <li><classname>ベースコンポーネント</classname></li>
  <li><classname>ベースバリューコンポーネント</classname></li>
  <li><classname>ベースフォームアイテム</classname></li>
  <li><classname>ベースリストアイテム</classname></li>
  <li><classname>ベースリスト</classname></li>
</ul>

<h3>ベースコンポーネント</h3>

<p>
<classname>ベースコンポーネント</classname>は全てのコンポーネントをサブクラスとして持つ中小クラスです。<classname>ベースコンポーネント</classname>は、多くの基本的な機能の名前を付けるために、スタイルを適用し、HTMLテキスト属性を定義し、フォーカスイベントを処理します。詳しくは、<code>lps/components/base/basecomponent.lzx</code>のソースコードを見てください。
</p>

<h3>ベースバリューコンポーネント</h3>

<p>
<classname>ベースバリューコンポーネント</classname>のサブクラスは、<code>value</code>（値）プロパティを持つものとして知られています。アイテム（項目）のインスタンスが表すのがvalue（値）です。アイテム（項目）が選択されると、親セクショングループのvalue（値）がこのvalue（値）にセットされます。<classname>ベースバリューコンポーネント</classname>は<method>getValue</method>メソッドを持っており、もしもどんな値もセットされない場合には、クラスのテキストをその値として返します。そのため、<attribute>value</attribute>属性を伴って取得されたvalue（値）は、<method>getValue</method>が返す値とは異なっているかもしれません。このため、<classname>ベースバリューコンポーネント</classname>のほとんどのサブクラスは、直接value属性にアクセスするのではなく、<method>getValue</method>が呼び出されることを要求します。
</p>

<example title="Basevaluecomponent example">
&lt;canvas debug="true" height="260"&gt;
  &lt;debug height="240"/&gt;
  &lt;include href="base/basevaluecomponent.lzx"/&gt;

  &lt;class name="myvaluecomponent" extends="basevaluecomponent"&gt;
    &lt;method event="oninit"&gt;
      Debug.write(this.name + ' text: "' + this.text + '"');
      Debug.write(this.name + ' value: "' + this.value + '"');
      Debug.write(this.name + ' getValue(): "' + this.getValue() + '"');
      Debug.write("");
    &lt;/method&gt;
  &lt;/class&gt;
  
  &lt;!-- Text is inherited from basecomponent, the superclass of --&gt;
  &lt;!-- basevalue component.                                    --&gt;
  &lt;myvaluecomponent name="one" text="this is the text"/&gt;

  &lt;!-- Set the value this time. Note that value is an expression type. --&gt;
  &lt;!-- Have to use quotes to set a string value.                       --&gt;
  &lt;myvaluecomponent name="two" value="'this is the value'"/&gt;

  &lt;!-- Set both text and value. --&gt;
  &lt;myvaluecomponent name="three" text="this is the text" 
                    value="'this is the value'"/&gt;
&lt;/canvas&gt;
</example>

<h3> ベースフォームアイテム </h3>

<p>
<classname>ベースフォームアイテム</classname>は<classname>ベースバリューコンポーネント</classname>のサブクラスです。
<classname>ベースフォームアイテム</classname>のインスタンスの値には、<tagname>form</tagname>タグを使ってアクセスしたり、記述したりできます。
もし、カスタムコンポーネントがフォーム内でアクセスされる必要がある場合には、<classname>ベースフォームアイテム</classname>をサブクラスにしてください。
ベースフォームアイテムの例：<classname>チェックボックス</classname>、<classname>ラジオグループ</classname>、<classname>コンボボックス</classname>。
<classname>ラジオボタン</classname>は<classname>ベースフォームアイテム</classname>ではなく、<classname>ベースバリューアイテム</classname>であることに注意してください。
なぜならば、ラジオボタンはその値を<classname>フォーム</classname>というより、むしろ<classname>ラジオグループ</classname>に渡すものだからです。
</p>

<h3>ベースリストアイテム</h3>

<p>
<classname>ベースリストアイテム</classname>は、<classname>ベースバリューコンポーネント</classname>の別のサブクラスです。
<classname>ベースリストアイテム</classname>のインスタンスは、一般的に<classname>ベースリスト</classname>内で使用されます。
ベースリストアイテムのインスタンスが選択される場合、そのインスタンス（ベースリスト/リスト）の親はセクションについて知らされます。
もし、カスタムコンポーネントがリストコンテキスト内でアクセスされるのが望ましければ、<classname>ベースリストアイテム</classname>をサブクラスにしてください。

ベースフォームアイテムの例: <classname>ラジオボタン</classname>, <classname>タブ要素</classname>, <classname>リスト要素</classname></p>
<h3> ベースリスト </h3>
<p>
<classname>ベースリスト</classname>は<classname>ベースフォームアイテム</classname>のサブクラスです。
<classname>ベースリスト</classname>は、<classname>タブスライダー</classname>や<classname>タブ</classname>のようなアイテムのリストを扱うどのようなコンポーネントにも使用されるけれども、
一般的に、<classname>ベースリスト</classname>のサブクラスはその値を（<classname>リスト</classname>や<classname>コンボボックス</classname>のような）フォームに渡します。
</p>

<h2>スライダーコンポーネントを書く</h2>

<p>
スライダーを例にとって、カスタムコンポーネントのデザインの仕方と書き方を見てみましょう。
<code>base/baseslider.lzx</code>あるいは<code>lz/slider.lzx</code>の中に、完全なコードがあります。
</p>

<h3>デザイン</h3>

<p>
まず最初に、スライダーを構成している異なるパーツについて考える必要があります。
スライダーをドラッグして調整するためのサム（親指）ボタンが必要です。
上に乗るサムを含めるように、スライダートラックが必要です。
最後に、トラックを保持するためのコンテナが必要です。
そのコンテナがスライダーコンポーネントであり、属性とスタイルをトラックやサムに渡します。
</p>

<p>スライダーの基本的なデザインはこんな感じです。</p>

<img class="illustration" src="images/slider.png"
     title="Basic design of custom slider"/>

<h3>ベースクラス</h3>

<h4>ベーススライダー</h4>

<p>
<classname>baseslider</classname>は<classname>slider</classname>のためのベースコンポーネントです。
</p>

<h5>フレームワーク</h5>

<p>スライダーの作成は、まずベース（値なし）クラスから始めて、<classname>basevaluecomponent</classname>を拡張します。
というのも、スライダーは値を持っているからです。</p>

<example title="Baseslider extends basevaluecomponent" extract="false">
&lt;class name="baseslider" <b>extends="basevaluecomponent"</b>&gt;
&lt;/class&gt;
</example>

<h5>属性</h5>
<p>トラックサイズとサムのための属性が必要です。</p>

<example title="Basic baseslider attributes" extract="false">
&lt;class name="baseslider" extends="basevaluecomponent" <b>width="200"</b>&gt;
  &lt;attribute <em>name="trackheight"</em> value="8" type="number"/&gt;
  &lt;attribute <em>name="thumbwidth"</em> value="10" type="number"/&gt;
  &lt;attribute <em>name="thumbheight"</em> value="18" type="number"/&gt;
&lt;/class&gt;
</example>

<p>
トラックはその幅を<classname>baseslider</classname>の幅に、高さを<code>trackheight</code>に拘束します。
サムはその幅と高さをそれぞれ<classname>baseslider</classname>の<code>thumbwidth</code>と<code>thumbheight</code>とに拘束します。
</p>

<p>スライダーが取り込む必要のあるその他の値：</p>

<dl>
  <dt><attribute>minvalue</attribute>（最小値）
</dt>
  <dd>スライダーの最小値</dd>
  <dt><attribute>maxvalue</attribute>（最大値）</dt>
  <dd>スライダーの最大値</dd>
  <dt><attribute>showfill</attribute></dt>
  <dd>スライダートラック内で、満たされたエリアを表示するブーリアン</dd>
  <dt><attribute>showvalue</attribute>（値表示）</dt>
  <dd>ユーザがドラッグした時のサムのトップにおける浮動小数点の値のテキストを表示するブーリアン</dd>
  <dt><attribute>showrange</attribute>（範囲表示）</dt>
  <dd>最小範囲と最大範囲の境界を表示するブーリアン</dd>
</dl>

<example title="More baseslider attributes" extract="false">
&lt;class name="baseslider" extends="basevaluecomponent" width="200"&gt;
  &lt;attribute name="trackheight" value="8" type="number"/&gt;
  &lt;attribute name="thumbwidth" value="10" type="number"/&gt;
  &lt;attribute name="thumbheight" value="18" type="number"/&gt;

  &lt;attribute <em>name="minvalue"</em> value="0" type="number"/&gt;
  &lt;attribute <em>name="maxvalue"</em> value="100" type="number"/&gt;
  &lt;attribute <em>name="showfill"</em> value="true"/&gt;
  &lt;attribute <em>name="showvalue"</em> value="true" type="boolean"/&gt;
  &lt;attribute <em>name="showrange"</em> value="true" type="boolean"/&gt;
&lt;/class&gt;
</example>

<h5>メソッド</h5>

<p>スライダーは、値を範囲のパーセンテージとして受け渡しするために、APIsを提供する必要があるでしょう。</p>

<example title="Percentage APIs" extract="false">
&lt;class name="baseslider" extends="basevaluecomponent" width="200"&gt;
  &lt;!-- attributes begin here --&gt;
  &lt;!-- ...                   --&gt;
  &lt;!-- attributes end here   --&gt;

  &lt;!--- Sets the value for the slider that must be within min and max.
        @param Number v: a number between the minimum and maximum value
        for the slider. --&gt;
  &lt;method <em>name="setValue"</em> args="v"&gt;
    if (this.value == v) return;
    // ensure in bounds
    v = math.max(v,this.minValue);
    v = math.min(v,this.maxValue);
    this.value = v;
    if (onvalue) onvalue.sendEvent();
    if (!isinited) return;
    <em>_adjustThumb();</em>
  &lt;/method&gt;

  &lt;!--- Set the value by percentage of range from min to max.
        @param Number p: a percentage between the min and the max. --&gt;
  &lt;method <em>name="setPercentage"</em> args="p"&gt;
    var diff = this.minValue-this.maxValue;
    setValue( diff*p + this.minValue );
  &lt;/method&gt;

  &lt;!--- Get the percentage of the range selected by the value.
        @return Number: the percentage selected. --&gt;
  &lt;method <em>name="getPercentage"</em>&gt;
    return (this.value-this.minValue) / (this.maxValue-this.minValue);
  &lt;/method&gt;

  &lt;!--- adjusts the thumb location
        @keywords private --&gt;
  &lt;method <em>name="_adjustThumb"</em>&gt;
    var perc = getPercentage();
    var x = Math.round( (this.width-track.thumb.width)*perc );
    <em>track.thumb.setX(x);</em>
  &lt;/method&gt;
&lt;/class&gt;
</example>

<p>
<method>_adjustThumb</method>メソッドはスライダーの値、あるいはスライダーのパーセンテージが変化するたびごとに呼ばれます。
そのため、サムはスライダーの範囲に関して正確な位置を保持しています。
<classname>baseslider</classname>はそのサブクラスが<varname>thumb</varname>と呼ばれるサムコードを含む<varname>track</varname>と呼ばれるトラックコードを含んでいることを仮定しています。
</p>

<p>
<method>_adjustThumb</method>はアンダースコアから始まることに注意してください。
このネーミングルールはメソッドや属性はコンポーネントの使用者にとってプライベートだと考えられるべきであるということを示しているのです。
<attribute>value</attribute>属性は<classname>basevaluecomponent</classname>から継承されています。
</p>

<h5> イベント </h5>

<p>
さて、スライダーはその最小値、最大値を受け渡しするためにAPIsのセットが必要です。
コンポーネントは、<glossterm>expression</glossterm>のタイプに前置詞“on”を付けることでイベントを宣言することができます。
例えば、幅を変えるときに使われるイベント名は<event>onwidth</event>となります。
イベント属性を<code>null</code>で初期化してください。宣言されていないイベントは、デバッガ警告を表示するでしょう。
</p>

<example title="Min/max value APIs and events " extract="false">
&lt;class name="baseslider" extends="basevaluecomponent" width="200"&gt;
  &lt;!-- attributes begin here --&gt;
  &lt;!-- ...                   --&gt;
  
  &lt;!-- Event handler when minvalue changes. --&gt; 
  &lt;attribute <em>name="onminvalue"</em> value="null" type="expression"/&gt;
  
  &lt;!-- Event handler when maxvalue changes. --&gt; 
  &lt;attribute <em>name="onmaxvalue"</em> value="null" type="expression"/&gt;

  &lt;!-- attributes end here   --&gt;

  &lt;method name="setValue" args="v"&gt;
    // setValue body
  &lt;/method&gt;

  &lt;method name="setPercentage" args="p"&gt;
    // setPercentage body
  &lt;/method&gt;

  &lt;method name="getPercentage"&gt;
    // getPercentage body
  &lt;/method&gt;

  &lt;method name="_adjustThumb"&gt;
    // _adjustThumb body
  &lt;/method&gt;

  &lt;!--- Get the minimum value of the slider.
        @return Number: the minimum value. --&gt;
  &lt;method <em>name="getMinValue"</em>&gt;
    return this.minValue;
  &lt;/method&gt;
  &lt;!--- Get the maximum value of the slider.
        @return Number: the maximum value. --&gt;
  &lt;method <em>name="getMaxValue"</em>&gt;
    return this.maxValue;
  &lt;/method&gt;

  &lt;!--- Set the minimum value.
        @param Number v: the minimum value. --&gt;
  &lt;method <em>name="setMinValue"</em> args="v"&gt;
    if (this.minValue == v) return;
    this.minValue = v;
    <em>if (this.onminvalue) this.onminvalue.sendEvent();</em>
    // adjust value
    if (this.minValue &gt; this.value) this.setAttribute("value",v);
    _adjustThumb();
  &lt;/method&gt;

  &lt;!--- Set the maximum value.
        @param Number v: the maximum value. --&gt;
  &lt;method <em>name="setMaxValue"</em> args="v"&gt;
    if (this.maxValue == v) return;
    this.maxValue = v;
    <em>if (this.onmaxvalue) this.onmaxvalue.sendEvent();</em>
    // adjust value
    if (this.value &gt; v) this.setAttribute("value",v);
    _adjustThumb();
  &lt;/method&gt;
&lt;/class&gt;
</example>

<p>このコード構造はイベントを送る際には一般的です。</p>

<example title="Sending events" extract="false">
    if (this.onmaxvalue) this.onmaxvalue.sendEvent();
</example>

<p>コンポーネントのユーザがそれをこのように定義した場合にのみイベントを送ります。</p>

<example title="Defining events in the slider" extract="false">
&lt;slider onminvalue="Debug.write('minvalue:', this.minvalue)"
        onmaxvalue="Debug.write('maxvalue:', this.maxvalue)"/&gt;
</example>

<h5><method>init</method> 対 <event>oninit</event></h5>

<p>スライダーは、初期化の間にそのサムの位置をセットする必要があります。
値をセットするだけでは、サムを正しい位置に配置したことにはならないので、<method>init</method>メソッドを使ってこれを行います。
</p>

<example title="Min/max value APIs and events " extract="false">
&lt;class name="baseslider" extends="basevaluecomponent" width="200"&gt;
  &lt;!-- attributes begin here --&gt;
  &lt;!-- ...                   --&gt;
  &lt;!-- attributes end here   --&gt;

  &lt;method name="init"&gt;
    super.init();
    // have to adjust thumb once at start 
    _adjustThumb();
  &lt;/method&gt;        

  &lt;!-- methods begin here --&gt;
  &lt;!-- ...                --&gt;
  &lt;!-- methods end here   --&gt;
&lt;/class&gt;
</example>

<p>
コンポーネントを書く際、<event>oninit</event>イベントを使うよりも<method>init</method>の使用を薦めます。
なぜならば、<event>oninit</event>が呼び出される順序は未定義ですが、それに対して<method>init</method>は同期に呼ばれるためきちんと定義されているからです。
 <method>init</method>を使ってコンポーネントを書くことにより、コンポーネントのどんなユーザであっても、
コンポーネントのinitコードのあとに呼ばれることが保障されている<event>oninit</event> コードを定義する可能性があります。
<method>init</method>を使う際には、ボディ内で<code>super.init()</code> を必ず呼び出すようにしてください。
そうしなければ、クラスが正しく初期化されない可能性があります。
</p>

<h4>ベーススライダートラック</h4>

<p>
スライダートラックはサムを含んでいます。
トラックの視覚的な様相については後ほどお話しします。
<classname>baseslidertrack</classname>のインスタンスは<classname>baseslidertrack</classname>内に含まれていることが期待され、そのクラスの親トラックの属性をそれ自身にセットします。
</p>

<example title="Baseslidertrack" extract="false">
&lt;!--- Baseslidertrack expects to be within a baseslider (or its
    subclass). In other words, its "classroot" should be a slider. --&gt;
&lt;class name="baseslidertrack" width="100%" bgcolor="0x333333" 
       height="${classroot.trackheight}"&gt;
  &lt;method name="init"&gt;
    super.init();
    classroot.track = this;
  &lt;/method&gt;
&lt;/class&gt;
</example>

<h4> ベーススライダーサム </h4>

<p>サムとは基本的にスライダートラックの上部に乗っているドラッグ可能なボタンのことです。スライダートラックはサムを含みます。</p>

<example title="Basesliderthumb" extract="false">
&lt;!--- Basesliderthumb expects to be within a baseslidertrack (or its
    subclass). In other words, its "classroot" should be a
    slidertrack. --&gt;
&lt;class name="basesliderthumb" <em>extends="button"</em> <em>focusable="false"</em>
       width="${parent.classroot.thumbwidth}" 
       height="${parent.classroot.thumbheight}"
       <em>onmousedown="thedragstate.apply();"</em>
       <em>onmouseup="thedragstate.remove();"</em>
       y="${(parent.height-height)/2}"&gt;

  &lt;!--- Toggles the floating value text when dragging thumb. Constrain
        showvalue to baseslider's showvalue: parent is track,
        parent.parent is slider container. --&gt;
  &lt;attribute <em>name="showvalue" value="${parent.parent.showvalue}"</em>/&gt;

  &lt;!--- @keywords private --&gt;
  &lt;dragstate <em>name="thedragstate"</em> drag_axis="x"&gt;
    &lt;text name="t"
         resize="true"
         x="${classroot.width/2-width/2}"
         y="-14"
         text="${parent.parent.parent.value}"
         visible="${classroot.showvalue}"
    /&gt;
  &lt;/dragstate&gt;

  &lt;!--- constrain to parents bounds, and adjust slider value when dragged
        @keywords private --&gt;
  &lt;method <em>name="setX"</em> args="x"&gt;
    var boundedx = x;
    if ( x &gt; parent.getWidth()-getWidth() ) {
      var constrainX = parent.getWidth()-getWidth();
      boundedx = constrainX;
    } else
    if (parent.x &gt; x) {
      boundedx =  parent.x;
    }
    super.setX(boundedx);

    //update slider value
    var perc = ( (x) / (parent.parent.width-width) );
    var val = Math.round( ( (perc)*(parent.parent.maxValue-parent.parent.minValue) )
                          + parseInt(parent.parent.minValue) );
    //only adjust value if user is dragging or left or right key is pressed
    if (thedragstate.isapplied || 
      LzKeys.isKeyDown("leftarrow") || 
      LzKeys.isKeyDown("rightarrow") ) {
      parent.parent.setValue(val);
    }
  &lt;/method&gt;
&lt;/class&gt;
</example>

<p>
技術的に言うと、<classname>basesliderthumb</classname>は本当はベースコンポーネントとは考えられません。
それというのも、<classname>button</classname>から拡張されているのでその視覚的な外観を無効にする方法がないのです。
デフォルトでは、<classname>basesliderthumb</classname>は<classname>button</classname>なのでキーボードのフォーカスが可能です。
しかしながら、実際<classname>baseslider</classname>コンポーネントの一部なので、<classname>basesliderthumb</classname>はこの属性をfalseにセットします。
</p>

<p>
<classname>basesliderthumb</classname>はドラッグ可能でなければならないので、<classname>dragstate</classname>はボディ内で宣言されます
。これはマウスが押された時に適応され、マウスが離れた時に除かれます。
</p>

<p>
サムは<classname>baseslidertrack</classname> (parent)に含まれると仮定し、それは順番に<classname>baseslider</classname> (parent.parent)に含まれます。
サムの<code>showvalue</code>は<code>baseslider</code>の<code>showvalue</code>に拘束されます。
</p>

<p>
<method>setX</method>メソッドはスライダーの正しい値をセットし、サムがその親の境界内に配置されたことを確認します。
</p>

<h3>lz（視覚）クラス</h3>

<img class="illustration" src="images/slider1.png"
     title="Enlarged view of custom slider"/>

<h4> スライダー </h4>

<p>
<classname>slider</classname>は、<classname>baseslider</classname>の視覚的なサブクラスです。
sliderは視覚的な要素を含むため、ここにスタイルが適応されます。
<method>_applystyle</method>メソッドは<code>slider</code>のトラックの色をセットします。
スタイルがどのような働きをするのかについての詳細は、スタイルの章を参照のこと。
</p>

<p>
<classname>slider</classname>は<classname>baseslidertrack</classname>かbaseslidertrackのサブクラスを定義し、そのインスタンスを含みます。
<classname>baseslidertrack</classname>は初期化の間に（<classname>baseslider</classname>r内に）それ自身のためのリファレンスを生成します。
</p>

<p>
<attribute>showrange</attribute>が真であれば、最小値と最大値がスライダーのそれぞれ左と右に表示されます。
</p>

<example title="Slider" extract="false">
&lt;!--- a slider component allowing for easy selection of a value within a range --&gt;
&lt;class name="slider" extends="baseslider"&gt;
  &lt;<em>slidertrack</em>/&gt;

  &lt;<em>state apply="${classroot.showrange}"</em>&gt;
      &lt;text y="${classroot.track.y + classroot.track.height + 2}"
            text="${classroot.minvalue}"/&gt;
      &lt;text y="${classroot.track.y + classroot.track.height + 2}" resize="true"
            x="${classroot.track.x+classroot.track.width-width}"
            text="${classroot.maxvalue}"/&gt;
  &lt;/<em>state</em>&gt;

  &lt;!--- @keywords private --&gt;
  &lt;method <em>name="_applystyle"</em> args="s"&gt;
    track.setbgcolor(s.bordercolor);
    track.background.setbgcolor(s.basecolor);
    track.filled.setbgcolor(s.selectedcolor);
  &lt;/method&gt;
&lt;/class&gt;
</example>

<h4>スライダートラック</h4>

<p>
<classname>slidertrack</classname>のインスタンスには3つのviewがあります。
</p>

<dl>
  <dt><varname>background</varname></dt>
  <dd>トラックの背景色</dd>
  <dt><varname>filled</varname></dt>
  <dd>満たされたトラックエリアの背景色.</dd>
  <dt><varname>thumb</varname></dt>
  <dd>
  トラックのドラッグ可なボタンである<classname>basesliderthumb</classname>のインスタンス
  </dd>
</dl>

<p>
このクラスは自身の<attribute>showfill</attribute>属性を、親の(<classname>slider</classname>) <attribute>showfill</attribute>属性に強制します。
</p>

<example title="Slidertrack" extract="false">
&lt;!--- the inner track on which the sliderthumb rides --&gt;
&lt;class name="slidertrack" <em>extends="baseslidertrack"</em>&gt;
  &lt;!--- @keywords private --&gt;
  &lt;attribute <em>name="showfill"</em> value="${parent.showfill}" type="number"/&gt;

  &lt;view name="background" bgcolor="red"
        height="${parent.height-(2*parent.classroot.bordersize)}"
        width="${parent.width-(2*parent.classroot.bordersize)}"
        x="${parent.classroot.bordersize}"
        y="${(parent.height-height)/2}"
  /&gt;
  &lt;!-- the filled area --&gt;
  &lt;view name="filled" bgcolor="0xff9933" opacity=".8" visible="${classroot.showfill}"
        height="${parent.height-(2*parent.classroot.bordersize)}"
        width="${Math.max(0,Math.min(classroot.thumb.x+classroot.thumb.width,parent.width)-
                                     (2*parent.classroot.bordersize))}"
        y="${(parent.height-height)/2}"
        x="${parent.classroot.bordersize}"
  /&gt;

  &lt;sliderthumb name="thumb"/&gt;
&lt;/class&gt;
</example>

<h4>スライダーサム</h4>

<p>
<classname>basesliderthumb</classname>は既に、<classname>button</classname>から借りた見た目と感じとを含んでいるため、
スライダーサムは<classname>basesliderthumb</classname>から自分自身をただ拡張することができます。
あるいは、スライダートラックは<classname>sliderthumb</classname>の代わりに<classname>basesliderthumb</classname>を宣言することができました。
</p>

<example title="Sliderthumb" extract="false">
&lt;!--- the visual thumb the user drags to select a value --&gt;
&lt;class name="sliderthumb" <em>extends="basesliderthumb"</em>&gt;
&lt;/class&gt;
</example>

<h3>スライダーを使う</h3>

<p>
完全なコードセットは<code>base/baseslider</code>とl<code>lz/slider.lzx</code>を確認してください。
</p>

<p>
以下の例では、スライダーコンポーネントの使い方を紹介します。</p>

<example title="Using slider">
&lt;canvas height="200"&gt;
  &lt;include href="lz/slider.lzx"/&gt;
  &lt;slider x="50" y="50" value="30"/&gt;
&lt;/canvas&gt;
</example>

</body>
</html>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2001-2004 Laszlo Systems, Inc.  All Rights Reserved.              *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
